﻿using Microsoft.AspNetCore.Http;
using Rbac.Repository.Admins;
using Rbac.Services.Admins.Dto;
using Rbac.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Rbac.Domain.Admins;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using IdentityModel;
using Microsoft.Extensions.Configuration;

namespace Rbac.Services.Admins
{
    public class AdminService: IAdminService
    {
        private readonly IAdminRepository adminRepository;
        private readonly IConfiguration configuration;
        private readonly IHttpContextAccessor httpContext;

        /// <summary>
        /// 抽象
        /// </summary>
        /// <param name="adminRepository"></param>
        public AdminService(IAdminRepository adminRepository, IConfiguration configuration, IHttpContextAccessor httpContext)
        {
            this.adminRepository = adminRepository;
            this.configuration = configuration;
            this.httpContext = httpContext;
        }

        /// <summary>
        /// 检查用户名是否可用
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        public bool CheckUserName(string UserName,int AdminId = 0)
        {
            return adminRepository.Query().Any(m => m.UserName == UserName && m.AdminId != AdminId);
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResultDto Create(CreateDto dto)
        {
            return Register(new RegisterDto
            {
                ConfirmPassword = dto.ConfirmPassword,
                Password = dto.Password,
                UserName = dto.UserName,
                FullName = dto.FullName,
                HeaderImage = dto.HeaderImage
            });
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResultDto Update(EditDto dto)
        {
            try
            {
                var admin = adminRepository.Query(dto.AdminId);

                //判断是否上传文件并删除旧文件
                if(dto.HeaderImage != admin.HeaderImage)
                {
                    if(File.Exists($"{Directory.GetCurrentDirectory()}/wwwroot{admin.HeaderImage}"))
                        File.Delete($"{Directory.GetCurrentDirectory()}/wwwroot{admin.HeaderImage}");
                }

                admin.FullName = dto.FullName;
                admin.UserName = dto.UserName;
                if (!string.IsNullOrEmpty(dto.Password))
                {
                    admin.Password = MD5Helper.MD5Hash(dto.Password);
                }
                admin.HeaderImage = dto.HeaderImage;
                adminRepository.Update(admin);
                return new ResultDto { Code = State.Success };
            }
            catch (Exception)
            {
                return new ResultDto { Code = State.Failed, Msg = "更新失败" };
            }            
        }

        public ResultDto ManyDelete(List<int> list)
        {
            try
            {
                adminRepository.ManyDelete(list);
                return new ResultDto { Code = State.Success };
            }
            catch (Exception e)
            {
                return new ResultDto { Code = State.Failed, Msg = e.Message };
            }
        }

        public ResultDto ManyDelete(List<AdminDto> list)
        {
            try
            {
                var admins = adminRepository.Query().Where(m => list.Select(x=>x.AdminId).Contains(m.AdminId)).ToList();
                admins.ForEach(m => {
                    //判断是否上传文件并删除旧文件
                    if (File.Exists($"{Directory.GetCurrentDirectory()}/wwwroot{m.HeaderImage}"))
                        File.Delete($"{Directory.GetCurrentDirectory()}/wwwroot{m.HeaderImage}");
                });
                adminRepository.ManyDelete(admins);
                return new ResultDto { Code = State.Success };
            }
            catch (Exception e)
            {
                return new ResultDto { Code = State.Failed, Msg = e.Message };
            }
        }

        public ResultDto Delete(int Id)
        {
            try
            {
                //删除头像
                var admin = adminRepository.Query(Id);
                if (File.Exists($"{Directory.GetCurrentDirectory()}/wwwroot{admin.HeaderImage}"))
                    File.Delete($"{Directory.GetCurrentDirectory()}/wwwroot{admin.HeaderImage}");

                adminRepository.Delete(Id);
                return new ResultDto { Code = State.Success };
            }
            catch (Exception)
            {
                return new ResultDto { Code = State.Failed, Msg = "删除失败" };
            }
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public ResultDto Register(RegisterDto dto)
        {
            //验证码是否正确
            //用户名是否可用
            var admin = adminRepository.QueryByName(dto.UserName);
            if(admin != null)
            {
                return new ResultDto { Code = State.Failed, Msg = "用户名已被使用" };
            }
            else
            {
                Admin entity = new Admin();
                //密码加密
                //数据初始化
                entity.FullName = dto.FullName;
                entity.UserName = dto.UserName.ToLower();
                entity.Password = MD5Helper.MD5Hash(dto.Password);
                entity.CreateTime = DateTime.Now;
                entity.HeaderImage = dto.HeaderImage;
                //调用仓储方法添加
                adminRepository.Create(entity);

                return new ResultDto { Code = State.Success, Msg = "注册成功" };
            }
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResultLoginDto Login(LoginDto dto)
        {
            var admin = adminRepository.QueryByName(dto.UserName);
            if (admin == null)
            {
                return new ResultLoginDto { Code = State.Failed, Msg = "无此用户" };
            }
            else
            {
                if(admin.Password == MD5Helper.MD5Hash(dto.Password))
                {
                    //更新末次登录IP和末次登录时间
                    admin.LastLoginIP = httpContext.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
                    admin.LastLoginTime = DateTime.Now;
                    adminRepository.Update(admin);


                    //身份信息认证
                    //写Session或Cookies换成JWT
                    IList<Claim> claims = new List<Claim> {
                        new Claim(JwtClaimTypes.Id,admin.AdminId.ToString()),
                        new Claim(JwtClaimTypes.Name,admin.UserName),
                        new Claim(ClaimTypes.Name,admin.UserName),
                    };

                    //JWT密钥
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:key"]));

                    //算法
                    var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    //过期时间
                    DateTime expires = DateTime.UtcNow.AddHours(10);


                    //Payload负载
                    var token = new JwtSecurityToken(
                        issuer: configuration["JwtConfig:Issuer"],
                        audience: configuration["JwtConfig:Audience"],
                        claims: claims,
                        notBefore: DateTime.UtcNow,
                        expires: expires,
                        signingCredentials: cred
                        );

                    var handler = new JwtSecurityTokenHandler();

                    //生成令牌
                    string jwt = handler.WriteToken(token);

                    return new ResultLoginDto { Code = State.Success, Msg = "登录成功", Token = jwt };
                }
                else
                {
                    return new ResultLoginDto { Code = State.Failed, Msg = "密码错误" };
                }
            }
        }

        public AdminDto Query(int Id)
        {
            var admin = adminRepository.Query(Id);
            return new AdminDto {
                FullName = admin.FullName,
                AdminId = admin.AdminId,
                CreateTime = admin.CreateTime,
                LastLoginIP = admin.LastLoginIP,
                LastLoginTime = admin.LastLoginTime,
                UserName = admin.UserName,
                HeaderImage = admin.HeaderImage
            };
        }

        public (List<AdminDto>,int) Page(AdminQueryDto queryDto, int PageIndex = 1,int PageSize = 10)
        {
            ///真分页
            var list = adminRepository.Query();

            if (!string.IsNullOrEmpty(queryDto.Keyword))
            {
                list = list.Where(m => m.FullName.Contains(queryDto.Keyword) || m.UserName.Contains(queryDto.Keyword));
            }

            if(queryDto.StartTime != null)
            {
                list = list.Where(m => m.CreateTime >= queryDto.StartTime);
            }

            if (queryDto.EndTime != null)
            {
                list = list.Where(m => m.CreateTime <= queryDto.EndTime);
            }

             var admins =   list.OrderByDescending(m => m.CreateTime).Skip((PageIndex - 1) * PageSize).Take(PageSize)
                            .Select(item => new AdminDto
                            {
                                AdminId = item.AdminId,
                                CreateTime = item.CreateTime,
                                FullName = item.FullName,
                                LastLoginIP = item.LastLoginIP,
                                LastLoginTime = item.LastLoginTime,
                                UserName = item.UserName,
                                HeaderImage = item.HeaderImage
                            }).ToList();

            return new(admins, list.Count());
        }
    }
}
